package com.kx.base.util;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


/**
 * @author Sun
 * 雪花算法的工具类：
 * 雪花算法一共分为五个部分
 * 第一部分：是1bit，就是一个0，没有任何意义。
 * 第二部分：是41bit的时间戳。
 * 第三部分：是5bit，机房id。
 * 第四部分：是5bit，机器id。
 * 第五部分：是12bit，表示序列号
 *          就是这个机房这个机器上，这一毫秒，同时产生的雪花算法的值的序列号。
 *          这说明雪花算法单机一毫秒并发4096.
 */
@Component
public class SnowFlakeUtil {

    /**
     * 机器id
     */
    @Value("${snowflake.worker:0}")
    private long workerId;

    /**
     * 机房id
     */
    @Value("${snowflake.dataCenterId:0}")
    private long dataCenterId;

    /**
     * 序号
     */
    private long sequence;

    /**
     * 雪花算法时间的起点
     * 它其实就是当初算法创立者创立此算法的那个时间点。
     * 因为时间戳只有41位，因此当此算法运行69年左右的时候，时间就会重复。
     * 软件开发，设计的程序，需要保证多长时间不出问题呢？20年。
     */
    private long twepoch=1627462055200L;


    /**
     * 机房id与机器id都是5位
     * bit=位
     * byte=字节=8位=8bit
     */
    private long workerIdBits=5L;
    private long dataCenteridBits=5L;

    /**
     * 求n为二进制的最大值，怎么求？
     * 2^n  1<<n  - 1
     *
     * 最好求数据不需要更多bit。
     * -1^(-1<<n)  =>  n个1
     * 原码：1000 0001
     * 反码：1111 1110
     * 补码：1111 1111
     *
     * 左移3位：
     *      1111 1000
     *   ^  1111 1111
     *---------------
     *      0000 0111
     */

    /**
     * 机器号的最大值
     */
    private long maxWorkId=-1L^(-1L<<workerIdBits);

    /**
     * 机房id的最大值
     */
    private long maxDataCenterId=-1L^(-1L<<dataCenteridBits);


    /**
     * 序列号的长度
     */
    private long sequenceBits=12L;


    /**
     * 序列号的最大值
     */
    private long maxSequence=-1L^(-1L<<sequenceBits);


    /**
     * 机器id左移位数
     */
    private long workerIdShift=sequenceBits;

    /**
     * 机房id左移位数
     */
    private long dataCenterIdShift=sequenceBits+workerIdBits;

    /**
     * 时间戳左移位数
     */
    private long timestampShift=sequenceBits+workerIdBits+dataCenteridBits;


    /**
     * 总体的记录的时间
     */
    private long lastTimestamp=-1L;

    /**
     * 获取时间的方法
     */
    private long time(){
        return System.currentTimeMillis();
    }

    /**
     * 获取一个新的时间
     */
    private long nextTime(long lastTimestamp){
        long timestamp=time();
        while(timestamp<=lastTimestamp){
            timestamp=time();
        }
        return timestamp;
    }

    /**
     * 生成与拼装雪花算法
     */
    public synchronized long nextId(){
        //获取当前时间
        long timestamp=time();
        //和上一次时间比较
        if(timestamp<lastTimestamp){
            return -1;
        }
        //1毫秒内的并发
        if(lastTimestamp==timestamp){
            sequence=(sequence+1)&maxSequence;
            if(sequence==0){
                //获取一个新的时间，因为这一毫秒sequence已经最大了
                timestamp=nextTime(lastTimestamp);
            }
        }else{
            sequence=0;
        }
        //记录这一次生成雪花算法id的时间
        lastTimestamp=timestamp;
        //拼装雪花算法的id
        return ((timestamp-twepoch)<<timestampShift)|
                (dataCenterId<<dataCenteridBits)|
                (workerId<<workerIdBits)|
                (sequence);
    }
}
